#region Using Statements
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using SgMotion;
using SgMotion.Controllers;
using SgMotion.Effects;

// Synapse Gaming namespaces
using SynapseGaming.LightingSystem.Core;
using SynapseGaming.LightingSystem.Editor;
using SynapseGaming.LightingSystem.Effects;
using SynapseGaming.LightingSystem.Lights;
using SynapseGaming.LightingSystem.Rendering;
using SynapseGaming.LightingSystem.Rendering.Forward;
#endregion

//----------------------------------------------------------------------
//---- Modified XNAnimation Library (based on: 0.7.0.0 BETA 2) ---------
//---- Original Creator: Bruno Evangelista -----------------------------
//---- Modified by: Tom Looman -----------------------------------------
//---- Changes: Sunburn Integration (for version 1.2.6) ----------------
//---- Updated sample & library code for Sunburn 1.2.6 (And XNA GS 3.1)-
//---- Link to original library: http://www.codeplex.com/xnanimation ---
//---- Link to my Blog: http://coreenginedev.blogspot.com --------------
//----------------------------------------------------------------------

namespace SgMotionSample
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class AnimationSample : Game
    {
        private GraphicsDeviceManager graphics;


        // Sunburn Fields
        private SceneState sceneState = new SceneState();
        private LightingSystemManager lightingSystem;
        private RenderManager renderManager;
        private LightingSystemEditor editor;
        private SplashScreenGameComponent splashScreen;

        // Text UI
        private SpriteBatch spriteBatch;
        private SpriteFont spriteFont;
        private SpriteFont spriteFontBig;

        // Input
        private KeyboardState keyboardState;
        private KeyboardState lastKeyboardState;

        private string message = "XNA Animation System";

        // SKINNED MODEL STUFF
        #region SkinnedModel stuff

        private int activeAnimationClip;

        private SkinnedModel skinnedModel;

        private AnimationController animationController;
        private float boneRotation = 0;

        #endregion

        private Matrix cameraView;
        private Matrix cameraProjection;

        #region Constructor
        public AnimationSample()
        {
            graphics = new GraphicsDeviceManager(this);

            #if XBOX360
            graphics.PreferredBackBufferWidth = 1280;
            graphics.PreferredBackBufferHeight = 720;
            #else
            graphics.PreferredBackBufferWidth = 1024;
            graphics.PreferredBackBufferHeight = 576;
            #endif
            graphics.PreferMultiSampling = true;

            lightingSystem = new LightingSystemManager(Services);
            renderManager = new RenderManager(graphics);
            editor = new LightingSystemEditor(Services, graphics, this);
            editor.MoveScale = 100.0f;

            splashScreen = new SplashScreenGameComponent(this, graphics);
            Components.Add(splashScreen);

            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }
        #endregion

        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            spriteFont = Content.Load<SpriteFont>("Fonts/Arial");
            spriteFontBig = Content.Load<SpriteFont>("Fonts/Calibri");

            // Load the skinned model
            skinnedModel = Content.Load<SkinnedModel>("Models/PlayerMarine");

            // Create an animation controller and start a clip
            animationController = new AnimationController(skinnedModel.SkeletonBones);
            animationController.StartClip(skinnedModel.AnimationClips["Idle"]);

            // Setup camera
            cameraView = Matrix.CreateLookAt(new Vector3(0, 15, 30), new Vector3(0, 10, 0), Vector3.Up);
            cameraProjection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, (float)graphics.GraphicsDevice.Viewport.Width
                / (float)graphics.GraphicsDevice.Viewport.Height, 1, 1000);

            // Add light Rig to your scene
            renderManager.LightManager.SubmitLightRig(Content.Load<LightRig>("Lights/light_rig"), ObjectLifeSpan.Scene);
        }

        #region Unload
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
            renderManager.Unload();
            editor.Unload();
            lightingSystem.Unload();
        }
        #endregion

        protected override void Update(GameTime gameTime)
        {
            // Sunburn Editor
            editor.Update(gameTime, ref cameraView, false);
            
            lastKeyboardState = keyboardState;
            keyboardState = Keyboard.GetState();

            if (keyboardState.IsKeyDown(Keys.Escape))
                Exit();

            if (keyboardState.IsKeyDown(Keys.Left) &&
                lastKeyboardState.IsKeyUp(Keys.Left))
            {
                activeAnimationClip = (activeAnimationClip - 1);
                if (activeAnimationClip < 0)
                    activeAnimationClip = skinnedModel.AnimationClips.Count - 1;

                // Change the current animation clip
                animationController.CrossFade(skinnedModel.AnimationClips.Values[activeAnimationClip],
                    TimeSpan.FromSeconds(0.3f));
            }
            else if (keyboardState.IsKeyDown(Keys.Right) &&
                lastKeyboardState.IsKeyUp(Keys.Right))
            {
                activeAnimationClip = (activeAnimationClip + 1) % skinnedModel.AnimationClips.Count;

                // Change the current animation clip
                animationController.CrossFade(
                    skinnedModel.AnimationClips.Values[activeAnimationClip],
                    TimeSpan.FromSeconds(0.3f));
            }

            if (keyboardState.IsKeyDown(Keys.PageUp))
            {
                message = "Custom Per-Bone Transformation";

                boneRotation += 0.02f;
            }
            else if (keyboardState.IsKeyDown(Keys.PageDown))
            {
                message = "Custom Per-Bone Transformation";

                boneRotation -= 0.02f;
            }

            if (keyboardState.IsKeyDown(Keys.F1))
            {
                message = "No Interpolation";
                animationController.TranslationInterpolation = InterpolationMode.None;
                animationController.OrientationInterpolation = InterpolationMode.None;
                animationController.ScaleInterpolation = InterpolationMode.None;
            }
            else if (keyboardState.IsKeyDown(Keys.F2))
            {
                message = "Linear Interpolation";
                animationController.TranslationInterpolation = InterpolationMode.Linear;
                animationController.OrientationInterpolation = InterpolationMode.Linear;
                animationController.ScaleInterpolation = InterpolationMode.Linear;
            }
            else if (keyboardState.IsKeyDown(Keys.F3))
            {
                message = "Cubic Interpolation";
                animationController.TranslationInterpolation = InterpolationMode.Cubic;
                animationController.OrientationInterpolation = InterpolationMode.Linear;
                animationController.ScaleInterpolation = InterpolationMode.Cubic;
            }
            else if (keyboardState.IsKeyDown(Keys.F4))
            {
                message = "Spherical Interpolation";
                animationController.TranslationInterpolation = InterpolationMode.Linear;
                animationController.OrientationInterpolation = InterpolationMode.Spherical;
                animationController.ScaleInterpolation = InterpolationMode.Linear;
            }


            if (keyboardState.IsKeyDown(Keys.D5) && lastKeyboardState.IsKeyUp(Keys.D5))
            {
                message = "Animation Looping Control";
                animationController.LoopEnabled = !animationController.LoopEnabled;
            }

            if (keyboardState.IsKeyDown(Keys.Tab) && lastKeyboardState.IsKeyUp(Keys.Tab))
            {
                message = "Forward and Backward Playback";

                if (animationController.PlaybackMode == PlaybackMode.Forward)
                    animationController.PlaybackMode = PlaybackMode.Backward;
                else
                    animationController.PlaybackMode = PlaybackMode.Forward;
            }

            if (keyboardState.IsKeyDown(Keys.Up))
            {
                message = "Animation Speed Control";
                animationController.Speed += 0.005f;
            }
            else if (keyboardState.IsKeyDown(Keys.Down))
            {
                message = "Animation Speed Control";
                animationController.Speed -= 0.005f;
                if (animationController.Speed < 0.1f)
                    animationController.Speed = 0.1f;
            }

            // Update the animation controller
            rotation += (float)gameTime.ElapsedGameTime.TotalSeconds * 0.8f;
            animationController.Update(gameTime.ElapsedGameTime, Matrix.Identity);

            base.Update(gameTime);
        }

        private float rotation = 0;

        protected override void Draw(GameTime gameTime)
        {
            // Display Splashscreen on start
            if (!SplashScreenGameComponent.DisplayComplete)
            {
                base.Draw(gameTime);
                return;
            }

            // Render Scene and submitted objects
            renderManager.SubmitRenderableObject(skinnedModel.Model, Matrix.Identity, Matrix.CreateRotationY(rotation),
                animationController.SkinnedBoneTransforms, ObjectVisibility.Rendered | ObjectVisibility.CastShadows, ObjectLifeSpan.Frame);
            sceneState.BeginFrameRendering(cameraView,
                cameraProjection, gameTime, null);
            editor.BeginFrameRendering(sceneState);
            renderManager.BeginFrameRendering(sceneState);

            renderManager.Render();

            renderManager.EndFrameRendering();
            editor.EndFrameRendering();
            sceneState.EndFrameRendering();

            Draw2D();

            base.Draw(gameTime);
        }

        #region Draw2D
        private void Draw2D()
        {
            spriteBatch.Begin();

            spriteBatch.DrawString(spriteFont,
                "Model: " + "Marine" + "    Animation: " +
                    skinnedModel.AnimationClips.Keys[activeAnimationClip], new Vector2(10, 10),
                Color.Blue);

            spriteBatch.DrawString(spriteFont, "Speed: ", new Vector2(10, 40), Color.White);
            spriteBatch.DrawString(spriteFont, "Looping: ", new Vector2(10, 60), Color.White);
            spriteBatch.DrawString(spriteFont, "Blending: ", new Vector2(10, 90), Color.White);
            spriteBatch.DrawString(spriteFont, "Playing: ", new Vector2(10, 130), Color.White);

            spriteBatch.DrawString(spriteFont, "" + (int) (animationController.Speed * 1000) * 0.001f,
                new Vector2(140, 40), Color.Red);
            spriteBatch.DrawString(spriteFont, "" + animationController.LoopEnabled, new Vector2(140, 60),
                Color.Red);
            spriteBatch.DrawString(spriteFont, "None", new Vector2(140, 90), Color.Red);
            spriteBatch.DrawString(spriteFont, "" + animationController.PlaybackMode,
                new Vector2(140, 130), Color.Red);

            spriteBatch.DrawString(spriteFontBig, message, new Vector2(20, 715), Color.Yellow);
            spriteBatch.End();
        }
        #endregion
    }
}